{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5a0287da",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 4层神经网络，多分类\n",
    "import matplotlib.pyplot as plt \n",
    "from sklearn.datasets import load_digits\n",
    "import numpy as np\n",
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "\n",
    "# load data\n",
    "digits = load_digits()\n",
    "\n",
    "# copied from notebook 02_sklearn_data.ipynb\n",
    "fig = plt.figure(figsize=(6, 6))  # figure size in inches\n",
    "fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)\n",
    "\n",
    "# plot the digits: each image is 8x8 pixels\n",
    "for i in range(64):\n",
    "    ax = fig.add_subplot(8, 8, i + 1, xticks=[], yticks=[])\n",
    "    ax.imshow(digits.images[i], cmap=plt.cm.binary)\n",
    "    \n",
    "    # label the image with the target value\n",
    "    ax.text(0, 7, str(digits.target[i]))\n",
    "    \n",
    "# 生成样本数据\n",
    "x,y=digits.data,digits.target\n",
    "y_true = np.array(y).astype(float)\n",
    "\n",
    "# one-hot编码\n",
    "t = np.zeros((x.shape[0], 10))\n",
    "t[np.where(y==0), 0] = 1\n",
    "t[np.where(y==1), 1] = 1\n",
    "t[np.where(y==2), 2] = 1\n",
    "t[np.where(y==3), 3] = 1\n",
    "t[np.where(y==4), 4] = 1\n",
    "t[np.where(y==5), 5] = 1\n",
    "t[np.where(y==6), 6] = 1\n",
    "t[np.where(y==7), 7] = 1\n",
    "t[np.where(y==8), 8] = 1\n",
    "t[np.where(y==9), 9] = 1\n",
    "# 生成神经网络模型\n",
    "class nn_model:\n",
    "    e=2e-3  # 学习率\n",
    "    n_epoch=1000 #迭代次数\n",
    "\n",
    "nn = nn_model()\n",
    "nn.n_input_dim = x.shape[1]       # 输入神经元大小 \n",
    "nn.n_output_dim = 10              # 输出神经元大小\n",
    "nn.n_hide_dim1 =16               # 隐层1神经元大小\n",
    "nn.n_hide_dim2 = 32              # 隐层2神经元大小\n",
    "nn.n_hide_dim3 = 8             # 隐层3神经元大小\n",
    "\n",
    "\n",
    "# 初始化权重序列\n",
    "nn.W1 = np.random.randn(nn.n_input_dim, nn.n_hide_dim1) / np.sqrt(nn.n_input_dim)\n",
    "nn.b1 = np.zeros((1, nn.n_hide_dim1))\n",
    "\n",
    "nn.W2 = np.random.randn(nn.n_hide_dim1, nn.n_hide_dim2) / np.sqrt(nn.n_hide_dim1)\n",
    "nn.b2 = np.zeros((1, nn.n_hide_dim2))\n",
    "\n",
    "nn.W3 = np.random.randn(nn.n_hide_dim2, nn.n_hide_dim3) / np.sqrt(nn.n_hide_dim2)\n",
    "nn.b3 = np.zeros((1, nn.n_hide_dim3))\n",
    "\n",
    "nn.W4 = np.random.randn(nn.n_hide_dim3, nn.n_output_dim) / np.sqrt(nn.n_hide_dim3)\n",
    "nn.b4 = np.zeros((1, nn.n_output_dim))\n",
    "\n",
    "# 定义激活函数sigmod函数\n",
    "def sigmod(x):\n",
    "    return 1.0/(1+np.exp(-x))\n",
    "\n",
    "# 前向传递 f(wx+b)\n",
    "def forward(n, x):\n",
    "    n.z1 = sigmod(x.dot(n.W1) + n.b1)\n",
    "    n.z2 = sigmod(n.z1.dot(n.W2) + n.b2)\n",
    "    n.z3 = sigmod(n.z2.dot(n.W3) + n.b3)\n",
    "    n.z4 = sigmod(n.z3.dot(n.W4) + n.b4)\n",
    "    return n\n",
    "\n",
    "# 生成预测值\n",
    "forward(nn, x)\n",
    "y_pred = np.argmax(nn.z4, axis=1)\n",
    "errordata=[]\n",
    "# 反向传播\n",
    "def backpropagation(n, x, t):\n",
    "    for i in range(n.n_epoch):\n",
    "        # 计算神经元的输出 \n",
    "        forward(n, x)\n",
    "        \n",
    "        # 输出损失值与准确率\n",
    "        L = np.sum((n.z4 - t)**2)\n",
    "        \n",
    "        y_pred = np.argmax(nn.z4, axis=1)\n",
    "        acc = accuracy_score(y_true, y_pred)\n",
    "        \n",
    "        \n",
    "        if i % 100 == 0:\n",
    "            print(\"epoch [%4d] L = %f, acc = %f\" % (i, L, acc))\n",
    "        \n",
    "        # 误差计算\n",
    "        d4 = n.z4*(1-n.z4)*(t - n.z4)\n",
    "        d3 = n.z3*(1-n.z3)*(np.dot(d4, n.W4.T))\n",
    "        d2 = n.z2*(1-n.z2)*(np.dot(d3, n.W3.T))\n",
    "        d1 = n.z1*(1-n.z1)*(np.dot(d2, n.W2.T))\n",
    "        \n",
    "        \n",
    "        # 更新权重\n",
    "        n.W4 += n.e * np.dot(n.z3.T, d4)\n",
    "        n.b4 += n.e * np.sum(d4, axis=0)\n",
    "        \n",
    "        n.W3 += n.e * np.dot(n.z2.T, d3)\n",
    "        n.b3 += n.e * np.sum(d3, axis=0)\n",
    "        \n",
    "        n.W2 += n.e * np.dot(n.z1.T, d2)\n",
    "        n.b2 += n.e * np.sum(d2, axis=0)\n",
    "        \n",
    "        n.W1 += n.e * np.dot(x.T, d1)\n",
    "        n.b1 += n.e * np.sum(d1, axis=0)\n",
    "        \n",
    "    \n",
    "nn.n_epoch = 2000\n",
    "backpropagation(nn, x, t)\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
